﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Unity.Collections;
using UnityEngine;

namespace Nave.Tecnique
{
    public static class AtlasCreator
    {
        private static Buff<Rect> s_buffOfUVs = new Buff<Rect>();

        private static byte[] s_Bytes = new byte[0];

        private static int s_widthOfAtlas = 0;

        /// <summary>
        /// 动态创建一个图集
        /// </summary>
        public static Texture2D CreateAtlas(Texture2D[] textures, int atlasWidth, out Rect[] rects)
        {
            if (textures == null || textures.Length == 0)
            {
                rects = null;
                return null;
            }

            s_widthOfAtlas = atlasWidth;
            s_buffOfUVs.Resize(textures.Length);
            rects = s_buffOfUVs.buff;

            var atlas = new Texture2D(s_widthOfAtlas, s_widthOfAtlas, textures[0].format, false);
   
            int blockSize = GetBlcokSize(atlas.format);

            //var rectangle = GetFreeArea(1,1);
            //这里需要根据 算法自动布局纹理的uv
            rects[0] = new Rect(0, 0f, 0.5f, 0.5f);
            rects[1] = new Rect(0.5f, 0f, 0.25f, 0.25f);
            rects[2] = new Rect(0.75f, 0f, 0.25f, 0.25f);

            CopyRawTextureData(textures[0], rects[0].xMin, rects[0].yMin, blockSize);
            CopyRawTextureData(textures[1], rects[1].xMin, rects[1].yMin, blockSize);
            CopyRawTextureData(textures[2], rects[2].xMin, rects[2].yMin, blockSize);

            atlas.LoadRawTextureData(s_Bytes);
            atlas.Apply(false, true);

            return atlas;
        }

        /// <summary>
        /// 根据布局的uv信息，拷贝texture的rawdata到大图集
        /// </summary>
        private static void CopyRawTextureData(Texture2D texture, float u, float v, int blockSize)
        {
            if (u < 0 || u >= 1f || v < 0 || v >= 1f) return;

            int pixelOfBlock = 4; //4*4作为一个块存储
            int numOfColu = texture.width / pixelOfBlock;
            int numOfRow = texture.height / pixelOfBlock;
            int totalNumOfColu = s_widthOfAtlas / pixelOfBlock;
            int block_x = (int)(u * totalNumOfColu);
            int block_y = (int)(v * totalNumOfColu);

            //一行一行遍历拷贝
            var bytes = texture.GetRawTextureData();
            int byteNumOfRow = numOfColu * blockSize;
            for (int i = 0; i < numOfRow; i++)
            {
                int dstindex = (block_x + (block_y + i) * totalNumOfColu) * blockSize;
                int srcindex = i * byteNumOfRow;
                Array.Copy(bytes, srcindex, s_Bytes, dstindex, byteNumOfRow);
            }
        }

        /// <summary>
        /// 根据纹理格式获取一个block的字节长度
        /// </summary>
        private static int GetBlcokSize(TextureFormat format)
        {
            int blcokBytes = 0;
            switch (format)
            {
                case TextureFormat.DXT1:
                case TextureFormat.ETC_RGB4:
                case TextureFormat.ETC2_RGB:
                    blcokBytes = 8;
                    s_Bytes = new byte[s_widthOfAtlas * s_widthOfAtlas / 2];
                    break;
                case TextureFormat.DXT5:
                case TextureFormat.ETC2_RGBA8:
                case TextureFormat.ASTC_RGB_4x4:
                case TextureFormat.ASTC_RGBA_4x4:
                    blcokBytes = 16;
                    s_Bytes = new byte[s_widthOfAtlas * s_widthOfAtlas];
                    break;
                default:
                    Debug.LogError($"不支持的合图格式 {format} ！！");
                    return 0;
            }
            return blcokBytes;
        }

        static IntegerRectangle GetFreeArea(int width, int height)
        {
            IntegerRectangle rectangle = new IntegerRectangle(0, 0, width, height);
            return rectangle;
        }

        public sealed class Buff<T>
        {
            public T[] buff = new T[0];

            public int length;
            public void Resize(int size)
            {
                if (buff.Length < size)
                {
                    var __buff = new T[size];
                    Array.Copy(buff, 0, __buff, 0, buff.Length);
                    buff = __buff;
                }
            }
        }
    }
}
